package com.demo.java.sql.dsl;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 自定义简单的面向对象的sql构建工具
 */
public class SqlBuilderTest {
    interface Sql {
        public static final String BLANK = " ";
        public static final String COMMA = ",";
    }
    interface Column {
        String column();
        String alias();
        public static Column create(String column) {
            return new DefaultColumn(column);
        }
    }
    @Data
    @AllArgsConstructor
    private static class DefaultColumn implements Column,Sql {
        private String column;
        private String alias;
        public static Column create(String column) {
            return new DefaultColumn(column);
        }
        public DefaultColumn(String column) {
            this.column = column;
        }
        public String column() {
            return this.column;
        }
        public String alias() {
            return this.alias;
        }
        public String toString() {
            if (Objects.nonNull(this.alias)) {
                return this.column + BLANK + "AS" + BLANK + this.alias;
            }
            return this.column;
        }
    }
    @Data
    @AllArgsConstructor
    private static class Select implements Sql {
        private Column[] columns;
        public static Select create(Column[] columns) {
            return new Select(columns);
        }
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("SELECT").append(BLANK);
            int i = 0;
            for (Column column : columns) {
                if (i++ > 0) {
                    sb.append(COMMA);
                }
                sb.append(column);
                if (Objects.nonNull(column.alias())) {
                    sb.append(BLANK).append("AS").append(BLANK).append(column.alias());
                }
            }
            return sb.toString();
        }
    }
    @Data
    @AllArgsConstructor
    private static class From implements Sql {
        private String tableName;
        private String alias;
        public static From create(String tableName) {
            return new From(tableName);
        }
        public static From create(String tableName, String alias) {
            return new From(tableName, alias);
        }
        public From(String tableName) {
            this.tableName = tableName;
        }
        public String toString() {
            Objects.requireNonNull(this.tableName);
            if (Objects.isNull(alias) || alias.trim().length() == 0) {
                return tableName;
            }
            return BLANK + "FROM" + BLANK + this.tableName + " AS " + this.alias;
        }
    }
    @Data
    @AllArgsConstructor
    private static class Limit implements Sql {
        private Integer limit;
        public static Limit create(Integer limit) {
            return new Limit(limit);
        }
        public String toString() {
            if (limit == null) {
                return BLANK;
            }
            return BLANK + "LIMIT" + BLANK + this.limit;
        }
    }
    @Data
    private static class SqlBuilder {
        private Select select;
        private From from;
        private Limit limit;

        public SqlBuilder select(Column ...columns) {
            this.select = columns.length == 0 ? this.createDefaultSelect() : Select.create(columns);
            return this;
        }
        private Select createDefaultSelect() {
            Column[] columns_ = new Column[]{DefaultColumn.create("*")};
            return Select.create(columns_);
        }
        public SqlBuilder select(List<Column> columns) {
            Objects.requireNonNull(columns);
            this.select = Select.create(columns.toArray(new Column[]{}));
            return this;
        }
        public SqlBuilder from(String tableName) {
            this.from = From.create(tableName);
            return this;
        }
        public SqlBuilder from(String tableName, String alias) {
            this.from = From.create(tableName, alias);
            return this;
        }
        public SqlBuilder limit(int limit) {
            this.limit = Limit.create(limit);
            return this;
        }
        public String build() {
            StringBuilder sql = new StringBuilder();
            if (Objects.isNull(this.select)) {
                this.select = this.createDefaultSelect();
            }
            sql.append(this.select);

            Objects.requireNonNull(this.from, "must call from method set query table name");
            sql.append(this.from);

            if (Objects.nonNull(this.limit)) {
                sql.append(this.limit);
            }
            return sql.toString();
        }
        public static SqlBuilder builder() {
            return new SqlBuilder();
        }
    }

    @Data
    @AllArgsConstructor
    static class ThingColumn implements Column {
        private String column;
        public String column() {
            return this.column;
        }
        public String alias() {
            return null;
        }
    }
    public static void main(String[] args) {

        List<Column> columns = new ArrayList<>();
        columns.add(Column.create("name"));
        columns.add(Column.create("age"));
        System.out.println(SqlBuilder.builder()
                .select(columns)
                .from("dept", "a")
                .limit(10)
                .build());

        Column[] columns1 = new Column[]{Column.create("name"), Column.create("age")};
        System.out.println(SqlBuilder.builder()
                .select(columns1)
                .from("dept", "a")
                .build());
    }
}
